#ifndef CALLINGCONTEXT
#define CALLINGCONTEXT

#include <vector>
#include "SymbolTable.hpp"

class Instruction;
class SymbolTable;
class CallingInstance;

/**
	@class CallingContext
	@brief classe de gestion des fonctions et procédures

	cette classe gère la définition globale des fonctions et procédures (symboles, code)
*/
class CallingContext
{
	public:
        /**
            @brief constructeur de la classe

            initialise les attributs à leur valeur par défaut et crée la table des symboles
        */
		CallingContext ();
		/**
            @brief destructeur de la classe

            détruit la classe ainsi que tout ce qui a été créé dynamiquement
            @todo libération de la mémoire
        */
		~CallingContext ();
		/**
            @brief création d'une instance de la fonction

            cette méthode va créer une instance de la fonction. Elle est utilisée lors d'un appel à cette fonction pour créer le contexte local de l'appel (en mémoire).
            @param [in] caller un pointeur sur le contexte local de l'appelant
		*/
		CallingInstance* getInstance ( CallingInstance* caller );
		/**
            @brief initialisation du code à exécuter

            initialise le code (les instructions) du corps de la fonction
            @param [in] code le pointeur sur l'instruction (ie le bloc de code)
        */
		void setCode ( Instruction* code );
		/**
            @brief initialisation du nom de la fonction

            initialise le nom de la fonction
            @param [in] index la position de l'identificateur associé à la fonction dans la table des identificateurs
        */
		void setName ( unsigned int index );
		/**
            @brief initialisation du type de retour de la fonction

            initialise le type de retour de la fonction
            @param [in] type le type de retour de la fonction
        */
		void setReturnType ( BaseType type );
		/**
            @brief ajout de paramètres

            ajoute un paramètre formel à la fonction
            @param [in] index la position de l'identificateur de ce paramètre dans la table des identificateurs
            @param [in] type le type de ce paramètre
            @todo gestion des erreurs si on a déjà ajouté au moins une variable locale (fin de l'en-tête de la fonction)
            @todo gestion des erreurs si l'identificateur est déjà présent
            @todo gestion des erreurs de typage
		*/
		void addParameter ( unsigned int index, Type type );
		/**
            @brief ajout de variables

            ajoute une variable locale à la fonction
            @param [in] index la position de l'identificateur de cette variable dans la table des identificateurs
            @param [in] type le type de cette variable
            @todo gestion des erreurs si l'identificateur est déjà présent
            @todo gestion des erreurs de typage
		*/
		void addVariable ( unsigned int index, Type type );
		/**
            @brief arité de la fonction

            renvoie le nombre d'argument à passer à la fonction
            @return le nombre d'argument
        */
        unsigned int getArity () const;
		/**
            @brief paramètre de la fonction

            renvoie la position dans la table des identificateurs du i-ème argument
            @param [in] idArg le rang de l'argument dans la fonction
            @return le position dans la table des identificateurs
        */
        unsigned int getParameterIndex ( const unsigned int idArg ) const;
		/**
            @brief accède au type d'un identificateur

            renvoie le type associé à un identificateur local de la fonction (ie paramètre formel ou variable)
            @param [in] index la position de l'identificateur dans la table des identificateurs
            @return le type associé à l'identificateur
            @todo gestion des erreurs si l'identificateur n'apparait pas dans la fonction
		*/
		Type getTypeOf ( unsigned int index ) const;
		/**
            @brief accède à la classe d'un identificateur

            renvoie la classe associée à un identificateur local de la fonction (ie paramètre formel ou variable)
            @param [in] index la position de l'identificateur dans la table des identificateurs
            @return la classe associée à l'identificateur
            @todo gestion des erreurs si l'identificateur n'apparait pas dans la fonction
		*/
		SymbolClass getCategoryOf ( const unsigned int index ) const;
		/**
            @brief accède au type de retour de la fonction

            renvoie le type du résultat de la fonction
            @return le type du résultat de la fonction
		*/
		BaseType getReturnType () const;
		/**
            @brief affichage de la fonction

            affiche, de façon lisible, les informations associées à cette fonction (en-tête, variables locales, instructions)
        */
		void display () const;
		friend class CallingInstance;
	private:
        /// position de l'identificateur associé au nom de la fonction
        unsigned int _name;
        /// le type de retour de la fonction
        BaseType _returnType;
        /// les instructions de la fonction
		Instruction* _code;
		/// la table des symboles locale de la fonction
		SymbolTable* _symbols;
		/// l'espace mémoire nécessaire pour les arguments et variables de la fonction
		unsigned int _memorySizeNeeded;
		/// l'ordre de déclaration des arguments et des variables
		std::vector < unsigned int > _declarationOrder;
};

#endif

